package com.gui.migrate;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.util.Queue;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * Created by Gui on 2017/7/23.
 */
public final class Context {
    private static final Logger logger = LoggerFactory.getLogger(Context.class);

    protected String sourceHost = "192.168.100.101";
    protected int sourcePort = 6379;
    protected String sourcePasswd = "123456";

    protected String targetHost = "192.168.100.102";
    protected int targetPort = 6379;
    protected String targetPasswd = null;

    protected String password = "123456";
    protected int listeningPort = 12345;

    protected String rdbPath = System.getProperty("user.dir");  // "D:\\dump.rdb"
    protected Queue<byte[]> aofQueue = new ConcurrentLinkedQueue<>();
    protected Queue<byte[]> rdbQueue = new ConcurrentLinkedQueue<>();
    private boolean breakWriteContext = false;

    protected String masterRunid;
    protected long masterOffset;
    protected long slaveOffset;

    private ReadContext readContext;
    private WriteContext writeContext;

    private Timer timer = null;
    private Object timerLock = new Object();

    public Context() {
        readContext = new ReadContext(this);
        writeContext = new WriteContext(this);
    }

    public void start() {
        try {
            readContext.start();
        } catch (Exception e) {
            logger.error(e.toString());
        }
    }

    protected void startReadRDB() {
        while (true) {
            if (rdbQueue.isEmpty() && breakWriteContext) {
                break;
            }
            if (rdbQueue.isEmpty()) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    logger.error(e.toString());
                }
                continue;
            }
            byte[] bytes = rdbQueue.poll();
            if (bytes != null) {
                try {
                    writeContext.sendBytes(bytes);
                } catch (IOException e) {
                    logger.error(e.toString());
                    writeContextError();
                    break;
                }
            }
        }
    }

    protected void finishReadRDB(File file) {

    }

    protected void startReadAOF() {
        this.beginReplyAckToMaster();
    }

    protected void brokeReadAOF() {
        this.stopReplyAckMaster();
    }

    //从服务器断开连接
    protected void hasDropSlave() {
        try {
            readContext.stop();
        } catch (IOException e) {
            logger.error(e.toString());
        }
    }

    //  向主服务器发送ack
    private void beginReplyAckToMaster() {
        synchronized (timerLock) {
            if (timer == null) {
                timer = new Timer();
                timer.schedule(new TimerTask() {
                    public void run() {
                        readContext.replyAckToMaster();
                    }
                }, 1000, 1000);
            }
        }
    }

    private void stopReplyAckMaster() {
        synchronized (timerLock) {
            if (timer != null) {
                timer.cancel();
                timer = null;
            }
        }
    }

    private void writeContextError() {
        try {
            readContext.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            writeContext.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


}
